package linker;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.Scanner;

import data.SimpleStatement;
import data.SimpleURI;
import data.Statement;

import edu.mit.jwi.Dictionary;
import edu.mit.jwi.IDictionary;
import edu.mit.jwi.item.IIndexWord;
import edu.mit.jwi.item.ISynset;
import edu.mit.jwi.item.IWord;
import edu.mit.jwi.item.IWordID;
import edu.mit.jwi.item.POS;

public class Linker {
	private IDictionary dict;
	private String version;
	private static Scanner cons = new Scanner(System.in);
	public Linker(URL wn_path) {
		dict = new Dictionary(wn_path);
		dict.open();
		version = "WN" + dict.getVersion().getMajorVersion()
				+ dict.getVersion().getMinorVersion();
	}

	public List<ISynset> linker(String c, int dis) {
		if (dis <= 0) {
			ArrayList<ISynset> ret = new ArrayList<ISynset>();
			IIndexWord idxWord = null;
			idxWord = dict.getIndexWord(c, POS.NOUN);

			if (idxWord == null)
				return ret;
			for (IWordID wordID : idxWord.getWordIDs()) {
				IWord word = dict.getWord(wordID);
				ret.add(word.getSynset());
			}

			return ret;
		} else {
			Iterator<IIndexWord> iter = dict.getIndexWordIterator(POS.NOUN);

			ArrayList<ISynset> ret = new ArrayList<ISynset>();
			IIndexWord idxWord = null;
			while (iter.hasNext()) {

				idxWord = iter.next();

				if (idxWord == null)
					return ret;
				if (Matcher.levenshteinMatcher(idxWord.getLemma(), c) <= dis) {
					for (IWordID wordID : idxWord.getWordIDs()) {
						IWord word = dict.getWord(wordID);
						ret.add(word.getSynset());
					}
				}
			}
			return ret;
		}
	}

	public String getDictVersion() {
		return version;
	}

	public static void main(String[] args) {

		if (args.length < 1) {
			System.out
					.println("please specify the path for config file as parameter");
			return;

		}
		String config = args[0];
		Properties pre = new Properties();
		try {
			pre.load(new FileInputStream(config));
		} catch (FileNotFoundException e) {
			System.out.println("cannot find config file");
			return;
		} catch (IOException e) {
			System.out.println("cannot open config file");
			return;
		}

		int dis = 0;
		if (pre.containsKey("distance"))
			dis = Integer.valueOf(pre.getProperty("distance"));
		String output = pre.getProperty("output");
		String input = pre.getProperty("input");
		String wn = pre.getProperty("wordNet");
		URL url;


		HashMap<String, ISynset> mathed= new  HashMap<String,ISynset>();
		
		try {
			url = new URL("file", null, wn);
		} catch (MalformedURLException e2) {
			System.out.println("invalid path");
			return;
		}

		Linker linker = new Linker(url);

		Parser par = new Parser(null);
		try {
			par.open(input);
		} catch (FileNotFoundException e) {
			System.out.println("cannot find input file");
			return;
		} catch (IOException e) {
			System.out.println("cannot open input file");
			return;
		}
		File outDir = new File(output);
		if (!outDir.exists())
			outDir.mkdir();
		else if (!outDir.isDirectory()) {
			System.out.println("output is not a directory");
			return;
		}
		File outFile;
		File errFile;
		File logFile;
		FileOutputStream out;
		FileOutputStream err;
		FileOutputStream log;
		outFile = new File(outDir, "linked.out");
		errFile = new File(outDir, "unlinked.out");
		logFile = new File(outDir, "log.out");

		int offset = 0;
		boolean re = false;
		if (logFile.exists()) {
			System.out.println("continue the work?[Y/N]");
			String ans = cons.nextLine();
			if (ans.equals("Y") || ans.equals("y")) {
				try {
					offset = (
							new FileInputStream(logFile)).read();
					re = true;

				} catch (FileNotFoundException e) {
					System.out.println("cannt read log file, start new work");
				} catch (IOException e) {
					System.out.println("cannt read log file, start new work");
				}
			}
		} else
			try {
				logFile.createNewFile();
			} catch (IOException e2) {

				System.out.println("cannot create log file");
			}

		if (!outFile.exists())
			try {
				outFile.createNewFile();
			} catch (IOException e1) {
				System.out.println("cannot create output file");
				return;
			}
		if (!errFile.exists())
			try {
				errFile.createNewFile();
			} catch (IOException e1) {
				System.out.println("cannot create output file");
				return;
			}
		try {
			if (re) {
				out = new FileOutputStream(outFile, true);
				err = new FileOutputStream(errFile, true);
			} else {
				out = new FileOutputStream(outFile, false);
				err = new FileOutputStream(errFile, false);
			}
			log =new FileOutputStream(logFile);
		} catch (FileNotFoundException e) {
			System.out.println("cannot find output file");
			return;
		}
		String prefix = "http://www.ontologyportal.org/WordNet.owl";

		System.out.println("processing...");
		int pos = 0;
		while (par.hasNext()) {

			pos++;

			
			Statement s = par.nextStatement();
			if (pos < offset)
				continue;
			try {
				log.getChannel().position(0);
				log.write(pos);
				log.flush();
			} catch (IOException e1) {
				System.out.println("cannt write log");
			}
			String sub;
			String obj;
			List<ISynset> synSet;
			ISynset syn;

			synSet = linker.linker(s.getSubject().getSurfix(), dis);

//			if(mathed.containsKey(s.getSubject().getSurfix()))
//				syn=mathed.get(s.getSubject().getSurfix());
			if (synSet.size() > 1)
				syn = choseSynset(s,s.getSubject().toString(), synSet);
			else if (synSet.size() < 1)
				syn = null;
			else
				syn = synSet.get(0);
			if (syn == null) {
				try {
					err.write(s.toString().getBytes());
					continue;
				} catch (IOException e) {
					System.out.println("cannot write output file");
					return;
				}
			}
			mathed.put(s.getSubject().getSurfix(), syn);
			sub = makeSurfix(linker, syn.getID().toString());

			synSet = linker.linker(s.getObject().getSurfix(), dis);
			if(mathed.containsKey(s.getObject().getSurfix()))
				syn=mathed.get(s.getObject().getSurfix());
			else if (synSet.size() > 1)
				syn = choseSynset(s,s.getObject().toString(), synSet);
			else if (synSet.size() < 1)
				syn = null;
			else
				syn = synSet.get(0);
			if (syn == null) {
				try {
					err.write(s.toString().getBytes());
					continue;
				} catch (IOException e) {
					System.out.println("cannot write output file");
					return;
				}
			}

			mathed.put(s.getObject().getSurfix(), syn);
			obj = makeSurfix(linker, syn.getID().toString());

			SimpleStatement ret = new SimpleStatement(
					new SimpleURI(prefix, sub), s.getPredicate(),
					new SimpleURI(prefix, obj));

			try {
				out.write(ret.toString().getBytes());
			} catch (IOException e) {
				System.out.println("cannot write log file");
			}
		}
		try {
			out.close();
			err.close();
			log.close();
		} catch (IOException e) {
			System.out.println("cannot close out put file");
			return;
		}
		cons.close();
		System.out.println("linking complete");
	}

	public static String makeSurfix(Linker l, String id) {
		return l.getDictVersion() + "-" + id.split("-")[1];
	}

	public static ISynset choseSynset(Statement s,String omic, List<ISynset> set) {


		while (true) {
			int i = -1;

			while (i < 0 || i > set.size()) {
				main_menu(s,omic, set);

				cons.reset();
				// i=1;
				i = cons.nextInt();

			}
			if (i <= 0) {
				return null;
			} else if (i <= set.size())
				return set.get(i - 1);
			else
				i = -1;
		}
	}

	private static void main_menu(Statement s,String omic, List<ISynset> set) {
		int i;
		System.out.println(set.size() + " matches found for omic item" + omic);
		System.out.println("[0]: No match found");
		for (i = 1; i <= set.size(); i++) {
			System.out.println("[" + i + "]" + ": " + set.get(i-1).toString());
			System.out.println("Description:"+set.get(i-1).getGloss().toString());
			System.out.println("Example: "+s.getSubject().getSurfix()+" "+ s.getPredicate().getSurfix()+" "+s.getObject().getSurfix());
		}
		System.out.println("Select number to see details or drop all matches");
	}

}
